#include "OpticalPathManager.h"

#include <iostream>
#include <utility>

namespace ai_sim {

// This function is used to build a map from pair(src, dst) to a Path,
// which consists of many relay path.
// In order to Reconfige the path, we should
// 1. Check whether each relay of the new path is free
// 2. Check whether the old relay, if exists, is free
// 2. Recinfigure each OXC on the path()
// We consider that the new path and the old path can have different
// number of relay
void OpticalPathManager::AddPath(EndComponentId src, EndComponentId dst,
                                 const Path& path) {
    // If the user want to add a new path from src to dst, in this case,
    // we only need to check whether the new path is being used.
    // check whether all relay on the new path are valid, and record the
    // connection to be added/removed
    SrcDstPair src_dst_pair =
        std::pair<EndComponentId, EndComponentId>(src, dst);
    for (const Relay& relay : path) {
        const DeviceId& device_id = relay.device_id;
        const Connection& connection = relay.connection;
        // Remove link first
        auto it = occupied_inport_to_outport_map_[device_id].find(connection.in_port_id);
        if (it != occupied_inport_to_outport_map_[device_id].end()) {
            int out_port = it->second;
            if (out_port != connection.out_port_id) {
                removed_change_set_[device_id].push_back(
                    Connection(connection.in_port_id, out_port));
                occupied_inport_to_outport_map_[device_id].erase(connection.in_port_id);
                occupied_outport_to_inport_map_[device_id].erase(out_port);
            }
        }
        it = occupied_outport_to_inport_map_[device_id].find(connection.out_port_id);
        if (it != occupied_outport_to_inport_map_[device_id].end()) {
            int in_port = it->second;
            if (in_port != connection.in_port_id) {
                removed_change_set_[device_id].push_back(
                    Connection(in_port, connection.out_port_id));
                occupied_inport_to_outport_map_[device_id].erase(in_port);
                occupied_outport_to_inport_map_[device_id].erase(connection.out_port_id);
            }
        }
        // Add link
        it = occupied_inport_to_outport_map_[device_id].find(connection.in_port_id);
        if (it == occupied_inport_to_outport_map_[device_id].end()) {
            added_change_set_[device_id].push_back(connection);
            occupied_inport_to_outport_map_[device_id].emplace(
                connection.in_port_id, connection.out_port_id);
            occupied_outport_to_inport_map_[device_id].emplace(
                connection.out_port_id, connection.in_port_id);            
        }

    }
}

}  // namespace ai_sim
